using System.Text;
using System.Net.Sockets;

namespace muduoDotNet
{
    /// <summary>
    /// Buffer类，用于数据的读写和缓冲区管理
    /// </summary>
    public class Buffer
    {
        private const int kInitialSize = 1024;
        private const int kCheapPrepend = 8;
        private byte[] _buffer;
        private int _readerIndex;
        private int _writerIndex;

        public Buffer(int initialSize = kInitialSize)
        {
            _buffer = new byte[kCheapPrepend + initialSize];
            _readerIndex = kCheapPrepend;
            _writerIndex = kCheapPrepend;
        }

        /// <summary>
        /// 可读字节数
        /// </summary>
        public int ReadableBytes => _writerIndex - _readerIndex;

        /// <summary>
        /// 可写字节数
        /// </summary>
        public int WritableBytes => _buffer.Length - _writerIndex;

        /// <summary>
        /// 前置空闲字节数
        /// </summary>
        public int PrependableBytes => _readerIndex;

        /// <summary>
        /// 确保有足够的可写空间
        /// </summary>
        /// <param name="len">需要的空间大小</param>
        public void EnsureWritableBytes(int len)
        {
            if (WritableBytes < len)
            {
                MakeSpace(len);
            }
        }

        /// <summary>
        /// 返回可读数据的起始位置
        /// </summary>
        /// <returns>可读数据的起始位置</returns>
        public Span<byte> Peek()
        {
            return _buffer.AsSpan(_readerIndex, ReadableBytes);
        }

        /// <summary>
        /// 读取指定长度的数据
        /// </summary>
        /// <param name="len">要读取的长度</param>
        /// <returns>读取的数据</returns>
        public byte[] Read(int len)
        {
            if (len > ReadableBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(len), "Not enough data to read");
            }

            var result = new byte[len];
            System.Buffer.BlockCopy(_buffer, _readerIndex, result, 0, len);
            _readerIndex += len;
            return result;
        }

        /// <summary>
        /// 读取所有数据
        /// </summary>
        /// <returns>读取的数据</returns>
        public byte[] ReadAll()
        {
            return Read(ReadableBytes);
        }

        /// <summary>
        /// 读取所有数据并转换为字符串
        /// </summary>
        /// <returns>读取的字符串</returns>
        public string ReadAllString()
        {
            return ReadString(ReadableBytes);
        }

        /// <summary>
        /// 读取指定长度的数据并转换为字符串
        /// </summary>
        /// <param name="len">要读取的长度</param>
        /// <returns>读取的字符串</returns>
        public string ReadString(int len)
        {
            var bytes = Read(len);
            return Encoding.UTF8.GetString(bytes);
        }

        /// <summary>
        /// 跳过指定长度的数据
        /// </summary>
        /// <param name="len">要跳过的长度</param>
        public void Skip(int len)
        {
            if (len > ReadableBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(len), "Not enough data to skip");
            }
            _readerIndex += len;
        }

        /// <summary>
        /// 检索指定长度的数据（移动读指针）
        /// </summary>
        /// <param name="len">要检索的长度</param>
        public void Retrieve(int len)
        {
            if (len > ReadableBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(len), "Not enough data to retrieve");
            }
            _readerIndex += len;
        }

        /// <summary>
        /// 检索指定长度的数据并返回字节数组
        /// </summary>
        /// <param name="len">要检索的长度</param>
        /// <returns>检索到的数据</returns>
        public byte[] RetrieveAsBytes(int len)
        {
            if (len > ReadableBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(len), "Not enough data to retrieve");
            }
            
            var result = new byte[len];
            System.Buffer.BlockCopy(_buffer, _readerIndex, result, 0, len);
            _readerIndex += len;
            return result;
        }

        /// <summary>
        /// 查看指定长度的数据（不移动读指针）
        /// </summary>
        /// <param name="len">要查看的长度</param>
        /// <returns>查看到的数据</returns>
        public byte[] PeekAsBytes(int len)
        {
            if (len > ReadableBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(len), "Not enough data to peek");
            }
            
            var result = new byte[len];
            System.Buffer.BlockCopy(_buffer, _readerIndex, result, 0, len);
            return result;
        }

        /// <summary>
        /// 获取所有可读数据并清空缓冲区
        /// </summary>
        /// <returns>所有可读数据的字符串表示</returns>
        public string RetrieveAllAsString()
        {
            var result = System.Text.Encoding.UTF8.GetString(_buffer, _readerIndex, ReadableBytes);
            Clear();
            return result;
        }

        /// <summary>
        /// 清空缓冲区
        /// </summary>
        public void Clear()
        {
            _readerIndex = kCheapPrepend;
            _writerIndex = kCheapPrepend;
        }

        /// <summary>
        /// 追加数据
        /// </summary>
        /// <param name="data">要追加的数据</param>
        public void Append(byte[] data)
        {
            EnsureWritableBytes(data.Length);
            System.Buffer.BlockCopy(data, 0, _buffer, _writerIndex, data.Length);
            _writerIndex += data.Length;
        }

        /// <summary>
        /// 追加字符串
        /// </summary>
        /// <param name="str">要追加的字符串</param>
        public void Append(string str)
        {
            var data = Encoding.UTF8.GetBytes(str);
            Append(data);
        }

        /// <summary>
        /// 前置数据
        /// </summary>
        /// <param name="data">要前置的数据</param>
        public void Prepend(byte[] data)
        {
            if (PrependableBytes < data.Length)
            {
                throw new NetException("Not enough prependable space");
            }
            _readerIndex -= data.Length;
            System.Buffer.BlockCopy(data, 0, _buffer, _readerIndex, data.Length);
        }

        /// <summary>
        /// 压缩缓冲区，将已读数据清除
        /// </summary>
        public void Shrink()
        {
            if (ReadableBytes < _buffer.Length / 2)
            {
                var newBuffer = new byte[kCheapPrepend + ReadableBytes];
                System.Buffer.BlockCopy(_buffer, _readerIndex, newBuffer, kCheapPrepend, ReadableBytes);
                _buffer = newBuffer;
                _writerIndex = kCheapPrepend + ReadableBytes;
                _readerIndex = kCheapPrepend;
            }
        }

        /// <summary>
        /// 确保有足够的空间
        /// </summary>
        /// <param name="len">需要的空间大小</param>
        private void MakeSpace(int len)
        {
            if (WritableBytes + PrependableBytes < len + kCheapPrepend)
            {
                // 空间不足，需要扩容
                var newCapacity = _writerIndex + len;
                var newBuffer = new byte[newCapacity];
                System.Buffer.BlockCopy(_buffer, _readerIndex, newBuffer, kCheapPrepend, ReadableBytes);
                _buffer = newBuffer;
                _readerIndex = kCheapPrepend;
                _writerIndex = kCheapPrepend + ReadableBytes;
            }
            else
            {
                // 空间足够，移动数据
                System.Buffer.BlockCopy(_buffer, _readerIndex, _buffer, kCheapPrepend, ReadableBytes);
                _readerIndex = kCheapPrepend;
                _writerIndex = kCheapPrepend + ReadableBytes;
            }
        }

        /// <summary>
        /// 从Socket读取数据到缓冲区
        /// </summary>
        /// <param name="socket">Socket对象</param>
        /// <returns>读取的字节数</returns>
        public int ReadFromSocket(Socket socket)
        {
            // 创建一个临时缓冲区，用于接收数据
            var tempBuffer = new byte[16 * 1024];
            try
            {
                var bytesRead = socket.Receive(tempBuffer, SocketFlags.None);
                if (bytesRead > 0)
                {
                    Append(tempBuffer.AsSpan(0, bytesRead).ToArray());
                }
                return bytesRead;
            }
            catch (SocketException ex)
            {
                // 处理非阻塞Socket的EWOULDBLOCK错误
                if (ex.SocketErrorCode == SocketError.WouldBlock ||
                    ex.SocketErrorCode == SocketError.IOPending ||
                    ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                {
                    return 0;
                }
                throw new NetException("Failed to read from socket", ex);
            }
        }

        /// <summary>
        /// 将缓冲区数据写入Socket
        /// </summary>
        /// <param name="socket">Socket对象</param>
        /// <returns>写入的字节数</returns>
        public int WriteToSocket(Socket socket)
        {
            if (ReadableBytes == 0)
            {
                return 0;
            }

            try
            {
                var bytesWritten = socket.Send(_buffer, _readerIndex, ReadableBytes, SocketFlags.None);
                if (bytesWritten > 0)
                {
                    _readerIndex += bytesWritten;
                    if (_readerIndex == _writerIndex)
                    {
                        // 所有数据都已写入，重置缓冲区
                        _readerIndex = kCheapPrepend;
                        _writerIndex = kCheapPrepend;
                    }
                }
                return bytesWritten;
            }
            catch (SocketException ex)
            {
                // 处理非阻塞Socket的EWOULDBLOCK错误
                if (ex.SocketErrorCode == SocketError.WouldBlock ||
                    ex.SocketErrorCode == SocketError.IOPending ||
                    ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                {
                    return 0;
                }
                throw new NetException("Failed to write to socket", ex);
            }
        }
    }
}